﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Common;
using Microsoft.Practices.EnterpriseLibrary.Validation;

namespace Arquitetura.Architectural.Model
{
    [DataContract(Name = "ResultOf{0}")]
    public class Result<T> : Result
    {
        #region Propriedade(s)
        [DataMember]
        public T Returned
        { get; set; }
        #endregion Propriedade(s)

        #region Construtor(es)
        public Result()
            : base() { }

        public Result(Result result)
            : base(result) { }

        public Result(T returned)
            : this(returned, true) { }

        public Result(ValidationResults validationResults)
            : base(validationResults) { }

        public Result(bool success)
            : base(success) { }

        public Result(T returned, bool success)
            : base(success)
        {
            Returned = returned;
        }

        public Result(Exception ex)
            : base(ex) { }
        #endregion Construtor(es)
    }

    [DataContract]
    public class Result
    {
        #region Propriedade(s)
        [DataMember]
        public bool Success
        { get; set; }

        [DataMember]
        public List<ResultMessage> Messages
        { get; set; }
        #endregion Propriedade(s)

        #region Construtor(es)
        public Result() :
            this(false) { }

        public Result(bool success)
        {
            Success = success;
            Messages = new List<ResultMessage>();
        }

        public Result(Exception exception)
            : this(false)
        {
            if (exception == null)
            {
                throw new ArgumentException("O parâmetro exception do tipo Exception não pode ser uma referência nula.");
            }

            Messages.Add(new ResultMessage(exception));
        }

        public Result(Result result)
            : this(result.Success)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", "O parâmetro result do tipo Resultado não pode ser uma referência nula.");
            }

            Messages.AddRange(result.Messages);
        }

        public Result(ValidationResults validationResults)
            : this(validationResults.IsValid)
        {
            if (validationResults == null)
            {
                throw new ArgumentNullException("validationResults", "O parâmetro validationResults não pode ser uma referência nula.");
            }

            if (!validationResults.IsValid)
            {
                ConsolidateValidationResult(validationResults);
            }
        }
        #endregion Construtor(es)

        #region Método(s)
        public void ConsolidateValidationResult(IEnumerable<ValidationResult> validationResults)
        {
            if (validationResults == null)
            {
                throw new ArgumentNullException("validationResults", "O parâmetro validationResults não pode ser uma referência nula.");
            }

            foreach (ValidationResult validationResult in validationResults)
            {
                Messages.Add(new ResultMessage(validationResult));
                ConsolidateValidationResult(validationResult.NestedValidationResults);
            }
        }

        public string ConsolidateMessages()
        {
            return ConsolidateMessages("\n");
        }

        public string ConsolidateMessages(string separador)
        {
            return ConsolidateMessages(separador, new StringBuilder()).ToString();
        }

        public StringBuilder ConsolidateMessages(string separador, StringBuilder stringBuilder)
        {
            if (String.IsNullOrEmpty(separador))
            {
                if (separador == null)
                {
                    throw new ArgumentNullException("separador", "O parâmetro separador do tipo string não pode ser uma referência nula.");
                }
                else
                {
                    throw new ArgumentException("separador", "O parâmetro separador do tipo string não pode ser uma string vazia.");
                }
            }

            if (stringBuilder == null)
            {
                throw new ArgumentException("stringBuilder", "O parâmetro stringBuilder do tipo StringBuilder não pode ser uma referência nula.");
            }

            ResultMessage lastMessage = Messages.Last();

            foreach (ResultMessage menssage in Messages)
            {
                menssage.ConsolidateInformations(separador, stringBuilder);
                if (!((Object)menssage).Equals((Object)lastMessage))
                {
                    stringBuilder.Append(separador);
                }
            }
            return stringBuilder;
        }

        public void Clear()
        {
            Success = true;
            Messages.Clear();
        }
        #endregion Método(s)
    }
}
